/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.area.field.shape;

import com.vividsolutions.jts.io.ParseException;
import nl.cloudfarming.client.area.field.pref.AreaFieldPreference;
import com.vividsolutions.jts.geom.MultiPolygon;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import nl.cloudfarming.client.area.field.AreaFieldModule;
import nl.cloudfarming.client.area.field.ParseWKTException;
import nl.cloudfarming.client.geoviewer.events.LayerEventKey;
import nl.cloudfarming.client.geoviewer.events.NewLayerEvent;
import nl.cloudfarming.client.logging.AppLogFactory;
import nl.cloudfarming.client.logging.AppLogger;
import nl.cloudfarming.client.model.FieldFile;
import nl.cloudfarming.client.util.MD5Sum;
import nl.cloudfarming.client.util.NotAFileException;
import nl.cloudfarming.eventbus.BaseGuiEventProducer;
import org.geotools.data.FeatureSource;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.opengis.feature.simple.SimpleFeature;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;

/**
 *
 * @author Timon Veenstra
 */
public class ShapeFileProcessor {

    // Messages
    private static final String LOGKEY_PROCESSING_SUMMARY_PROCESSEDMSG = "shape.fileprocessor.loginfo.process_end";
    private static final String LOGKEY_PROCESSING_START = "shape.fileprocessor.loginfo.process_start";
    private static final String LOGKEY_PROCESSING_PARSE_ERROR = "shape.fileprocessor.logerror.process_error";
    private final File shapeFile;
    private final LayerEventProducer layerEventProducer = new LayerEventProducer();
    private static final AppLogger LOG = AppLogFactory.getLogger(AreaFieldModule.class);
    private static final String DEFAULT_SHAPE_NAME = NbBundle.getMessage(AreaFieldModule.class, "shape.fileprocessor.default_shape_name");

    public ShapeFileProcessor(File shapeFile) {
        this.shapeFile = shapeFile;
    }

    public void process() throws NotAFileException {

        ShapefileDataStore shpDataStore = null;
        if (shapeFile.isFile()) {
            try {
                LOG.info(LOGKEY_PROCESSING_START, shapeFile.getName());

                String checkSum = MD5Sum.getHex(MD5Sum.createChecksum(new FileInputStream(shapeFile)));
                final FieldFile plotFile = new FieldFile();
                plotFile.setChecksum(checkSum);
                plotFile.setFileCreated(new Date(shapeFile.lastModified()));
                plotFile.setFileName(shapeFile.getName());
                plotFile.setFileRead(new Date());
                //
                // create a dataprovider for this import
                //
                ImportDataProvider importDataProvider = new ImportDataProvider(plotFile);
                //
                // import the shapes into the dataprovider
                //
                shpDataStore = new ShapefileDataStore(shapeFile.toURI().toURL());
                String typeName = shpDataStore.getTypeNames()[0];
                FeatureSource featureSource = shpDataStore.getFeatureSource(typeName);
                FeatureCollection result = featureSource.getFeatures();
                FeatureIterator iterator = result.features();
                while (iterator.hasNext()) {
                    SimpleFeature feature = (SimpleFeature) iterator.next();
                    Shape shape = parseShape(feature);
                    importDataProvider.addShape(shape);
                }
                iterator.close();

                LOG.info(LOGKEY_PROCESSING_SUMMARY_PROCESSEDMSG, shapeFile.getName());

                NewLayerEvent event = new NewLayerEvent(importDataProvider.getLayer());
                layerEventProducer.triggerEvent(event);
            } catch (NoSuchAlgorithmException ex) {
                StringBuilder exBuilder = new StringBuilder("No such algorithmException ");
                exBuilder.append(shapeFile.getName());
                LOG.error(exBuilder.toString(), ex);
            } catch (IOException ex) {
                StringBuilder exBuilder = new StringBuilder("IOException while reading ");
                exBuilder.append(shapeFile.getName());
                LOG.error(exBuilder.toString(), ex);
            }
        } else {
            StringBuilder sb = new StringBuilder("The File-object [");
            sb.append(shapeFile.getPath());
            sb.append("] passed to this ShapeFileProcessor instance is not a File");
            throw new NotAFileException(sb.toString());
        }

    }

    /**
     * 
     * @param payload
     * @return
     */
    public Shape parseShape(SimpleFeature payload) throws ParseWKTException {
        int attIndexPlotPoly = payload.getFeatureType().indexOf(AreaFieldPreference.SHAPE_ATT_POLYGON.getValue());
        int attIndexPlotName = payload.getFeatureType().indexOf(AreaFieldPreference.SHAPE_ATT_NAME.getValue());
        MultiPolygon polygon = null;
        if (attIndexPlotPoly >= 0) {
            polygon = (MultiPolygon) payload.getAttribute(attIndexPlotPoly);
        }
        String shapeName = DEFAULT_SHAPE_NAME;
        if (attIndexPlotName >= 0) {
            shapeName = (String) payload.getAttribute(attIndexPlotName);
        }

        try {
            Shape shape = new Shape(polygon.toString());
            shape.setName(shapeName);
            shape.setType(Shape.ShapeType.SKIP);
            return shape;
        } catch (ParseException ex) {
            Exceptions.printStackTrace(ex);
            LOG.error(LOGKEY_PROCESSING_PARSE_ERROR, shapeFile.getName());
            throw new ParseWKTException("Failed creating shape from multipolygon: " + polygon.toString(), ex);
        }
    }

    private class LayerEventProducer extends BaseGuiEventProducer {
        public LayerEventProducer() {
            super(LayerEventKey.class);
        }
    }
}
